package main

import (
	"gameServer/config"   // 配置包，提供配置文件、环境变量的加载与管理
	"gameServer/database" // 数据库包，提供数据库工厂、管理器及具体实现
	"gameServer/env"
	"gameServer/log" // 日志包，提供日志记录功能
	"time"           // 时间包，用于控制程序运行时长
)

/*
数据库演示程序：展示如何通过配置加载、数据库工厂创建并管理多类型数据库（主库、缓存、日志库），
并对MySQL和Redis执行简单的CRUD操作，验证数据库连接与基本功能。
*/

func main() {
	// 从配置文件读取配置
	fileConfig := config.NewFileConfig("config.json")
	if err := fileConfig.Load(); err != nil {
		// 使用标准输出作为后备
		log.Fatalf("Failed to load config: %v", err)
	}
	// 创建环境变量配置
	envConfig := env.NewEnvConfig("GAME")

	// 创建配置管理器
	manager := config.NewManager(envConfig, fileConfig)

	// 创建网关配置
	gateConfig := config.NewGateConfig()
	gateConfig.LoadFromManager(manager)

	// 初始化日志系统 - 使用配置文件中的日志配置
	logConfig := &log.LogConfig{
		Level:      gateConfig.Log.Level,
		Format:     gateConfig.Log.Format,
		Output:     gateConfig.Log.Output,
		FilePath:   gateConfig.Log.FilePath,
		MaxSize:    gateConfig.Log.MaxSize,
		MaxAge:     gateConfig.Log.MaxAge,
		MaxBackups: gateConfig.Log.MaxBackups,
	}

	// 初始化日志系统
	if err := log.InitFromConfig(logConfig); err != nil {
		log.Fatalf("Failed to initialize log system: %v", err)
	}

	log.Info("Starting database demo...")
	log.Infof("Log configuration: level=%s, output=%s, file=%s",
		logConfig.Level, logConfig.Output, logConfig.FilePath)

	// -------------------------- 配置加载流程结束 --------------------------

	// 创建数据库工厂：用于根据配置动态创建不同类型的数据库实例
	factory := database.NewFactory()

	// 创建主数据库（MainDB）：通常用于存储核心业务数据（如用户信息、订单）
	// 参数1：全局管理器（此处代码可能有误，应为数据库名称，推测是笔误）
	// 参数2：数据库名称"main"（用于在全局管理器中标识该实例）
	// 参数3：主数据库配置（来自gateConfig.Database.Main）
	mainDB, err := factory.CreateDatabaseFromConfig(
		database.GlobalManager(), // 推测此处应为数据库名称参数，可能是代码笔误
		"main",
		&gateConfig.Database.Main,
	)
	if err != nil {
		log.Fatalf("Create main database error: %s", err.Error()) // 创建失败则退出
	}

	// 创建缓存数据库（CacheDB）：通常用于存储高频访问的临时数据（如用户在线状态、会话）
	cacheDB, err := factory.CreateDatabaseFromConfig(
		database.GlobalManager(), // 同上，推测为笔误
		"cache",
		&gateConfig.Database.Cache,
	)
	if err != nil {
		log.Fatalf("Create cache database error: %s", err.Error())
	}

	// 创建日志数据库（LogDB）：专门用于存储系统日志、业务操作日志
	logDB, err := factory.CreateDatabaseFromConfig(
		database.GlobalManager(), // 同上，推测为笔误
		"log",
		&gateConfig.Database.Log,
	)
	if err != nil {
		log.Fatalf("Create log database error: %s", err.Error())
	}

	log.Info("All databases connected successfully") // 记录所有数据库创建并连接成功

	// 测试数据库连接有效性（心跳检测）
	// 测试主数据库连接
	if err := mainDB.Ping(); err != nil {
		log.Fatalf("Ping main database error: %s", err.Error()) // 主库连接失败则退出
	} else {
		log.Info("main databases connected successfully")
	}

	// 测试缓存数据库连接
	if err := cacheDB.Ping(); err != nil {
		log.Errorf("Failed to ping cache database: %v", err) // 缓存库连接失败仅记录错误，不退出
	} else {
		log.Info("Cache database ping successful")
	}

	// 测试日志数据库连接
	if err := logDB.Ping(); err != nil {
		log.Errorf("Failed to ping log database: %v", err) // 日志库连接失败仅记录错误，不退出
	} else {
		log.Info("Log database ping successful")
	}

	// 根据数据库类型执行对应的演示操作（MySQL或Redis）
	// 从全局管理器中获取所有数据库实例（返回map：名称→实例）
	for name, db := range database.GlobalManager().GetAllDatabase() {
		switch db.Type() { // 根据数据库类型（DBType）分支处理
		case database.DBTypeMySQL:
			log.Infof("Running MySQL demo for database: %s", name)
			runMySQLDemo(db) // 执行MySQL演示逻辑
		case database.DBTypeRedis:
			log.Infof("Running Redis demo for database: %s", name)
			runRedisDemo(db) // 执行Redis演示逻辑
		}
	}

	// 程序运行30秒（模拟实际服务运行，保持数据库连接）
	log.Info("Database demo running for 30 seconds...")
	time.Sleep(30 * time.Second)

	// 关闭所有数据库连接，释放资源
	if err := database.CloseAllDatabase(); err != nil {
		log.Errorf("Failed to close databases: %v", err)
	} else {
		log.Info("All database connections closed successfully")
	}

	log.Info("Database demo completed") // 记录程序结束日志
}

// runMySQLDemo 执行MySQL数据库的演示操作：创建表、插入数据、查询数据
func runMySQLDemo(db database.Database) {
	// 将通用Database接口转换为具体的MySqlDatabase类型（类型断言）
	// 原因：需调用MySQL特有的方法（如Exec、QueryRow）
	mysqlDB, ok := db.(*database.MySqlDatabase)
	if !ok {
		log.Error("Invalid MySQL database instance") // 类型转换失败则记录错误
		return
	}

	// 创建测试表：users表（包含id、username、email、created_at字段）
	// IF NOT EXISTS确保表不存在时才创建，避免重复创建错误
	createTableSQL := `
	CREATE TABLE IF NOT EXISTS users (
		id INT AUTO_INCREMENT PRIMARY KEY,
		username VARCHAR(50) NOT NULL,
		email VARCHAR(100) NOT NULL,
		created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
	)`

	// 执行建表SQL
	if _, err := mysqlDB.Exec(createTableSQL); err != nil {
		log.Errorf("Failed to create table: %v", err)
		return
	}

	// 插入测试数据：向users表插入一条用户记录
	insertSQL := "INSERT INTO users (username, email) VALUES (?, ?)" // 使用?作为占位符防止SQL注入
	result, err := mysqlDB.Exec(insertSQL, "testuser", "test@example.com")
	if err != nil {
		log.Errorf("Failed to insert data: %v", err)
		return
	}

	// 获取插入数据的自增ID（通过LastInsertId()）
	lastID, _ := result.LastInsertId()
	log.Infof("Inserted user with ID: %d", lastID)

	// 查询刚插入的数据：根据ID查询用户信息
	querySQL := "SELECT id, username, email, created_at FROM users WHERE id = ?"
	row := mysqlDB.QueryRow(querySQL, lastID) // QueryRow用于单行查询

	// 定义结构体存储查询结果
	var user struct {
		ID        int64
		Username  string
		Email     string
		CreatedAt time.Time
	}

	// 将查询结果扫描到结构体中（Scan的参数顺序需与SELECT字段顺序一致）
	if err := row.Scan(&user.ID, &user.Username, &user.Email, &user.CreatedAt); err != nil {
		log.Errorf("Failed to query user: %v", err)
		return
	}
	log.Infof("Found user with ID: %d", user.ID)
}

// runRedisDemo 执行Redis数据库的演示操作：设置键值、获取键值、操作哈希表
func runRedisDemo(db database.Database) {
	// 将通用Database接口转换为具体的RedisDatabase类型
	redisDB, ok := db.(*database.RedisDatabase)
	if !ok {
		log.Error("Invalid Redis database instance")
		return
	}

	// 1. 演示Redis键值对操作
	key := "test:key"              // 键名（通常用:分隔命名空间，如"test:key"）
	value := "Hello Redis"         // 键值
	expiration := 10 * time.Minute // 过期时间（10分钟后自动删除）

	// 设置键值对
	if err := redisDB.Set(key, value, expiration); err != nil {
		log.Errorf("Failed to set value: %v", err)
		return
	}

	// 获取键值
	result, err := redisDB.Get(key)
	if err != nil {
		log.Errorf("Failed to get value: %v", err)
		return
	}
	log.Infof("Got value: %s", result)

	// 2. 演示Redis哈希表操作（哈希表适合存储对象类数据，如用户信息）
	hashKey := "test:user:1" // 哈希表键名（表示ID为1的测试用户）

	// 向哈希表中设置字段和值（name=john Doe，email=john@example.com）
	if err := redisDB.HSet(hashKey, "name", "john Doe", "email", "john@example.com"); err != nil {
		log.Errorf("Failed to set value: %v", err)
		return
	}

	// 获取哈希表中所有字段和值
	userData, err := redisDB.HGetAll(hashKey)
	if err != nil {
		log.Errorf("Failed to get value: %v", err)
		return
	}
	log.Infof("Got value: %s", userData)
}
